package org.groovymud.shell.telnetd;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;

import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

import net.wimpi.telnetd.net.ConnectionEvent;
import net.wimpi.telnetd.shell.Shell;

import org.apache.log4j.Logger;
import org.groovymud.object.alive.Player;
import org.groovymud.object.registry.Registry;
import org.groovymud.shell.delegates.MudRequestDelegate;
import org.groovymud.shell.io.TerminalIOFactory;

/**
 * This shell is passed on to from the log in shell, and is where the user is
 * prompted for all their commands in the mud.
 * 
 * 
 * 
 * @author matt
 */
public class MudShell extends ShellBridge {

	protected static final String BEAN_NAME = "mudShell";
	private final static Logger logger = Logger.getLogger(MudShell.class);
	private WeakReference<Player> referenceToPlayer;
	
	private final MudRequestDelegate mudRequestDelegate;

    public MudShell(Registry registry, TerminalIOFactory ioFactory, MudRequestDelegate mudRequestDelegate) {
        super(registry, ioFactory);
        this.mudRequestDelegate = mudRequestDelegate;
    }

    public void doRun() {

		HashMap environment = getConnection().getConnectionData().getEnvironment();
        referenceToPlayer = new WeakReference<Player>((Player) environment.get("player"));
		Player player = referenceToPlayer.get();
		environment.put(org.groovymud.shell.Shell.PROMPT_VAR, ">");
        getMudRequestDelegate().setEnvironment((Map<Object, Object>) environment);
        try {
            getMudRequestDelegate().execute(player, getTerminalIO());
        } catch (Exception e) {
            logger.error(e, e);
        } finally {
            LoginContext lc = (LoginContext) environment.get("loginContext");
            try {
				lc.logout();
			} catch (LoginException e) {
				logger.error(e, e);
			} finally {
				getConnection().close();
			}
		}
	}

	public static Shell createShell() {
		return (Shell) getApplicationContext().getBean(BEAN_NAME);
	}

	public void connectionIdle(ConnectionEvent ce) {
		try {
			getTerminalIO().write("CONNECTION_IDLE");
			getTerminalIO().flush();
		} catch (IOException e) {
			logger.error(e, e);
		}
	}

	// this implements the ConnectionListener!
	public void connectionTimedOut(ConnectionEvent ce) {
		try {
			Player player = referenceToPlayer.get();
			getTerminalIO().writeln("Sorry, you timed out. See ya!");
			getRegistry().dest(player);
			getTerminalIO().write("CONNECTION_TIMEDOUT");
			getTerminalIO().flush();
			// close connection
			getConnection().close();
		} catch (Exception ex) {
			logger.error("connectionTimedOut()", ex);
		}
	}

	public void connectionLogoutRequest(ConnectionEvent ce) {
		try {
			getTerminalIO().write("CONNECTION_LOGOUTREQUEST");
			getTerminalIO().flush();
		} catch (IOException e) {
			logger.error(e, e);
		}

	}

	public void connectionSentBreak(ConnectionEvent ce) {
		try {
			getTerminalIO().write("CONNECTION_BREAK");
			getTerminalIO().flush();
		} catch (IOException e) {
			logger.error(e, e);
		}

	}

	/**
	 * @return the mudRequestDelegate
	 */
	public MudRequestDelegate getMudRequestDelegate() {
		return mudRequestDelegate;
	}

}
